home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
strategy
/
xnetbris.00
/
xnetbris
/
server.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-19
|
14KB
|
588 lines
/*
* This is the server part of Netbrisk.
Copyright (C) 1995 Brendan Bartlett
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "brisk.h"
#include "server.h"
static int client_fd[MAX_PLAYERS];
static int numplayers = MAX_PLAYERS;
static int play_type;
static struct card **suits[4];
static struct card **deck;
static int deckp; /* pointer to the top of the deck */
static unsigned char scores[4]; /* 0, 1 used for team, upto 4 used if chaos */
static struct card brisk; /* the current brisk */
static struct card **table; /* the cards currently down on the table */
static struct struct_hand **hand; /* list of cards the players have */
static int sock_fd;
static int start_server(unsigned short int port, int num_players); /* returns 0 on error */
static void shuffle_cards(void);
/* Brisk-playing routines */
static void play_brisk(void);
static int decide_winner(int, char *); /* looks at the global table variable */
static void score_table(struct packet *);
static void get_card(struct card *holder, int player, int dontdeal, int tablepos); /* gets a card from the client */
static int legal_move(struct card *played, int player); /* returns -1 for illegal, index if ok */
static int deal_card(struct struct_hand *rec_card, int player, int cardnum);
int handler(int);
void main(int, char *[]);
int handler(int signum)
{
fprintf(stderr, "got SIGPIPE, cleaning up\n");
/* do cleanup here */
exit(0);
}
void main(int argc, char *argv[])
{
int port = 10000, i, j;
struct packet p;
signal(SIGPIPE, handler);
if(argc == 1)
{
printf("usage %s: <numplayers> <play type> <port>\n", argv[0]);
printf(" where numplayers is either 2 or 4 and play type is one of \"chaos\" or \"team\"\n");
printf(" port is optional, use only if default does not work.\n");
exit(0);
}
numplayers = atoi(argv[1]);
if(numplayers != 2 && numplayers != 4)
{
fprintf(stderr, "Bad argument %d, the number of players must be either 2 or 4.\n", numplayers);
exit(0);
}
if(strcmp(argv[2], "chaos") == 0)
play_type = CHAOS;
else if(strcmp(argv[2], "team") == 0)
play_type = TEAM;
else
{
printf("Bad argument [%s], should be either \"chaos\" or \"team\"\n", argv[2]);
exit(0);
}
if(numplayers == 2 && play_type == TEAM)
{
printf("Cannot play 2 players and team.\n");
exit(0);
}
if(argc == 4)
port = atoi(argv[3]);
for(i = 0; i < 4; i++)
{
scores[i] = 0;
suits[i] = malloc(sizeof(struct card *) * CARDS_SUIT);
for(j = 0; j < CARDS_SUIT; j++)
{
suits[i][j] = malloc(sizeof(struct card));
suits[i][j]->suit = i;
suits[i][j]->weight = j + 1;
}
}
table = malloc(sizeof(struct card *) * numplayers);
hand = malloc(sizeof(struct struct_hand *) * numplayers);
for(i = 0; i < numplayers; i++)
{
table[i] = malloc(sizeof(struct card));
hand[i] = malloc(sizeof(struct struct_hand));
}
shuffle_cards();
/*
for(i = 0; i < 3; i++)
fprintf(log, "player %d: [%d %d] [%d %d] [%d %d]\n", i, hand[i]->cards[0]->suit, hand[i]->cards[0]->weight, hand[i]->cards[1]->suit, hand[i]->cards[1]->weight, hand[i]->cards[2]->suit, hand[i]->cards[2]->weight);
*/
printf("Starting Netbrisk SERVER (Version %1.2f) on port %i, play_type %d, %d players\n", VERSION, port, play_type, numplayers);
if(!start_server(port, numplayers))
{
printf("start_server failed!\n");
exit(0);
}
/* The server has to tell the clients what cards they have by DEAL_TYPE packets */
for(i = 0; i < 3; i++)
for(j = 0; j < numplayers; j++)
if(!deal_card(hand[j], j, i))
printf("deal_card error!\n");
/* Now, after all the cards are "delt", the server selects the brisk */
p.type = MOVE_TYPE;
p.data.move.player = 5;
memcpy(&brisk, deck[deckp], sizeof(struct card));
memcpy(&p.data.move.play_card, &brisk, sizeof(struct card));
deckp--;
deck[0] = &brisk;
for(j = 0; j < numplayers; j++)
write(client_fd[j], &p, sizeof(struct packet));
play_brisk();
exit(0);
}
static void play_brisk(void)
{
int turn = 0, winner = 0, i = 0, j; /* The current players turn */
struct packet p;
char order[4];
/*
for(tabindex = 0, turn = winner; turn < numplayers; turn = ( (turn == numplayers - 1) ? winner : (turn + 1) % numplayers), tabindex = (tabindex + 1) % numplayers)
*/
while(1)
{
turn = winner;
/* no more cards on deck */
if(deckp == -1)
break;
for(i = 0; i < numplayers; i++, turn = (turn + 1) % numplayers)
{
get_card(table[i], turn, 0, i);
order[i] = turn;
}
winner = decide_winner(winner, order);
}
/* play out the last hand */
p.type = LAST_HAND;
for(i = 0; i < numplayers; i++)
write(client_fd[i], &p, sizeof(struct packet));
for(j = 0; j < 3; j++)
{
for(i = 0, turn = winner; i < numplayers; i++, turn = (turn + 1) % numplayers)
{
get_card(table[i], turn, 1, i);
order[i] = turn;
}
winner = decide_winner(winner, order);
}
/* game is complete */
for(i = 0; i < numplayers; i++)
{
p.type = END_GAME;
p.data.score.scores[0] = scores[0];
p.data.score.scores[1] = scores[1];
write(client_fd[i], &p, sizeof(struct card));
close(client_fd[i]);
}
printf("Game over - final score %d to %d.\n", scores[0], scores[1]);
}
/* Looks at the table[] array and figures out who has won
* based on the current brisk and who went first
*
* Informs the clients of the winner.
*
* Returns the player # of the winner
*/
static int decide_winner(int oldwin, char *order)
{
struct card *winning = table[0];
int ccheck, playerptr, winplayer = order[0], i;
struct packet out;
for(ccheck = 1, playerptr = (oldwin + 1) % numplayers; ccheck < numplayers; ccheck++, playerptr = (playerptr + 1) % numplayers)
{
if(table[ccheck]->suit == winning->suit)
{
if(table[ccheck]->weight > winning->weight)
{
winplayer = order[ccheck];
winning = table[ccheck];
}
}
else if(table[ccheck]->suit == brisk.suit)
{
winplayer = order[ccheck];
winning = table[ccheck];
}
}
out.type = SCORE_UPDATE;
out.data.score.lastwin = winplayer;
score_table(&out);
for(ccheck = 0; ccheck < numplayers; ccheck++)
write(client_fd[ccheck], &out, sizeof(struct packet));
for(ccheck = 0; ccheck < numplayers; ccheck++)
{
read(client_fd[ccheck], &out, sizeof(struct packet));
if(out.type != OK)
fprintf(stderr, "Client did not respond to SCORE_UPDATE correctly.\n");
}
return winplayer;
}
/*
* This is private to decide_winner.
*
* Fills in the packet 'p' with the appropiate scores for the cards on the table
*
*/
static void score_table(struct packet *out)
{
int cardnum, score, i;
char scoretab[] = { 0, 0, 0, 0, 0, 2, 3, 4, 10, 11 };
for(score = 0, cardnum = 0; cardnum < numplayers; cardnum++)
score += scoretab[table[cardnum]->weight];
if(play_type == CHAOS)
{
scores[out->data.score.lastwin] += score;
for(i = 0; i < numplayers; i++)
out->data.score.scores[i] = scores[i];
}
else
{
unsigned char teamtab[] = { 0, 1, 0, 1 };
scores[teamtab[out->data.score.lastwin]] += score;
for(i = 0; i < numplayers; i++)
out->data.score.scores[teamtab[i]] = scores[teamtab[i]];
}
}
/*
static void print_hands(void)
{
int i, j;
for(i = 0; i < numplayers; i++)
{
printf("player %d: ", i);
for(j = 0; j < 3; j++)
printf(" %d %d", hand[i]->cards[j]->suit, hand[i]->cards[j]->weight);
printf("\n");
}
}
*/
/*
* Gets a card from the given client.
* Checks if the card is indeed in the given players hand.
*
* Before returning, a new card is given to the client
* (in both the server data types and via a packet to the client)
*
* Also, given that the card which the client played is legal for it to play
* (ie. is in its hand), this will inform the other clients of the card that
* this client has played (via MOVE_TYPE packets)
*
* Returns the card that the client has played.
*/
static void get_card(struct card *holder, int player, int dontdeal, int tablepos)
{
struct packet in, out;
int pcard = 0, i;
out.type = MOVE_EXPECTED;
out.data.move.player = player;
for(i = 0; i < numplayers; i++)
if(i != player)
write(client_fd[i], &out, sizeof(struct packet));
write(client_fd[player], &out, sizeof(struct packet));
/* Now, we wait for the client to send back a card */
read(client_fd[player], &in, sizeof(struct packet));
/* If the client send a bogus card, loop until it gives a card in its hand */
if((pcard = legal_move(&in.data.move.play_card, player)) == -1)
do
{
out.type = ILLEGAL_MOVE;
write(client_fd[player], &out, sizeof(struct packet));
read(client_fd[player], &in, sizeof(struct packet));
}
while( (pcard = legal_move(&in.data.move.play_card, player)) == -1);
out.type = OK;
out.data.ok.cardpos = pcard;
write(client_fd[player], &out, sizeof(struct packet));
/* save the played card into the given pointer */
memcpy(holder, &in.data.move.play_card, sizeof(struct card));
/* Deal out a new card to the player */
if(! dontdeal)
deal_card(hand[player], player, pcard);
in.data.move.tablepos = tablepos;
/* Inform the clients of the card which the other client has played */
for(i = 0; i < numplayers; i++)
write(client_fd[i], &in, sizeof(struct packet));
return;
}
/*
* This function will only tell if the 'played' card is inside the hand of the
* player who played the card
*
* Returns the card (in the server data types) the client played.
* or -1 for no such card (illegal move)
*/
static int legal_move(struct card *played, int player)
{
int i, rtn = -1;
for(i = 0; i < 3; i++)
if(played->suit == hand[player]->cards[i]->suit && played->weight == hand[player]->cards[i]->weight)
rtn = i;
return rtn;
}
void shuffle_cards(void)
{
int shuffle[NUM_CARDS + 1], flag[NUM_CARDS + 1];
int i;
deck = malloc(sizeof(struct card *) * NUM_CARDS + 1);
for(i = 0; i < NUM_CARDS + 1; i++)
deck[i] = malloc(sizeof(struct card));
srand(time(NULL));
memset(flag, 0, sizeof(int) * (NUM_CARDS + 1));
for (i=0; i != 40; i++)
{
while(1)
{
shuffle[i]=rand() % 40;
if (flag[shuffle[i]] == 0)
{
flag[shuffle[i]] = 1;
break;
}
}
}
for(i = 0; i < 40; i++)
if(shuffle[i] < 10)
{
deck[i+1]->suit = SUN;
deck[i+1]->weight = shuffle[i];
}
else if(shuffle[i] < 20)
{
deck[i+1]->suit = SWORD;
deck[i+1]->weight = shuffle[i] - 10;
}
else if(shuffle[i] < 30)
{
deck[i+1]->suit = BONE;
deck[i+1]->weight = shuffle[i] - 20;
}
else
{
deck[i+1]->suit = CUP;
deck[i+1]->weight = shuffle[i] - 30;
}
/* set up the pointer to the top of the deck array */
deckp = NUM_CARDS;
}
/* This routine takes a player number and a structure and deals this player
* a new card.
*
* Returns 0 on failure, 1 for success
*/
static int deal_card(struct struct_hand *rec_card, int player, int cardnum)
{
struct packet p;
if(cardnum < 0 || cardnum > 3)
return 0;
rec_card->cards[cardnum] = deck[deckp];
p.type = DEAL_TYPE;
p.data.deal.rec_place = cardnum;
memcpy(&p.data.deal.deal_card, rec_card->cards[cardnum], sizeof(struct card));
write(client_fd[player], &p, sizeof(struct packet));
deckp--;
return 1;
}
int start_server(unsigned short int port, int num_players)
{
int optval, namelen;
struct sockaddr_in addr;
struct protoent *proto;
int player_count;
struct packet p;
p.type = INFORM_TYPE;
p.data.inform.numplayers = numplayers;
p.data.inform.play_type = play_type;
proto = getprotobyname("tcp");
if(proto == 0)
{
fprintf(stderr, "tcp not supported here!\n");
return 0;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
sock_fd = socket(AF_INET, SOCK_STREAM, proto->p_proto);
if(sock_fd == -1)
{
fprintf(stderr, "cannot open socket!\n");
return 0;
}
/* allow the local port to be re-used by the server over and over */
if(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1)
{
perror("setsockopt");
return 0; /* not reached */
}
if(bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
perror("bind");
return 0;
}
if(listen(sock_fd, 1) == -1)
{
perror("listen");
return 0;
}
for(player_count = 0; player_count < num_players; player_count++)
{
printf("Waiting for player %d to connect to port %i.\n", player_count+1, port);
client_fd[player_count] = accept(sock_fd, (struct sockaddr *)&addr, &namelen);
/*
write(client_fd[player_count], VERSION, strlen(VERSION));
*/
p.data.inform.yournumber = player_count;
write(client_fd[player_count], &p, sizeof(struct packet));
}
close(sock_fd);
return 1;
}